import { createApp } from 'vue'
import { AppVisibility, Loading, LocalStorage, Notify, Quasar, copyToClipboard } from 'quasar'
import { mdiAlertOutline } from '@quasar/extras/mdi-v6'
import mitt from 'mitt'
import options from '../../.quasar/quasar-user-options'

export const loginRouteName = 'login'
const msgKey = 'message'

const defContentType = 'application/json; charset=UTF-8'
let publicPath = process.env.VITE_APP_PUBLICPATH
if (publicPath) {
  publicPath = publicPath.match(/\w+/)
  if (publicPath && publicPath[0]) {
    publicPath = publicPath[0]
  }
}

export const storeUserInfoKey = `freeUi-FrontEnd-userInfo${publicPath ? `-${publicPath}` : ''}`

function createMittApp(...args) {
  const app = createApp(...args)
  app.use(Quasar, options)
  const bus = mitt()
  app.$on = bus.on
  app.$off = bus.off
  app.$emit = bus.emit
  return app
}

/**
 * 存储当前用户信息
 * userInfo不传或传null为清除
 */
function setUserInfo(userInfo = null) {
  if (userInfo) {
    LocalStorage.set(storeUserInfoKey, userInfo)
  } else {
    LocalStorage.remove(storeUserInfoKey)
  }
}

/**
 * 获取当前用户信息
 */
function getUserInfo() {
  try {
    return JSON.parse(localStorage.getItem(storeUserInfoKey))?.userInfo
  } catch (e) {}
}

/**
 * 显示默认的全屏等待动画
 */
function defShowLoading(opt = {}) {
  Loading.show({ delay: 0, spinnerSize: '2.7rem', ...opt })
}

/**
 * 隐藏默认的全屏等待动画
 */
function defHideLoading() {
  Loading.hide()
}

const defFailTip = '操作失败，请稍后重试！'
const defErrorTip = '系统开小差，请稍后重试！'

/**
 * 显示默认的失败通知
 */
function defFail(msg = defFailTip) {
  if (typeof msg !== 'string') {
    msg = msg[msgKey] || defFailTip
  }
  notifyWarning(msg)
}

/**
 * 显示默认的错误通知
 */
function defError(msg = defErrorTip) {
  if (typeof msg !== 'string') {
    msg = msg[msgKey] || defErrorTip
  }
  notifyError(msg)
}

function handleTokenErr() {
  if (!window._tokenErrTimeout) {
    defFail('登录信息有误或已失效，请重新登录！')
  }
}

function handleError(msg, handler = defError) {
  if (handler !== false) {
    (typeof handler == 'function' ? handler : defError)(msg)
  }
}

const defIcon = 'favicon.ico'

function tryNotify({ title, body = 'frontend-vite', icon = defIcon, callBack }) {
  return new Promise((resolve, reject) => {
    if (window.Notification) {
      Notification.requestPermission().then((permission) => {
        if (permission === 'granted') {
          // 如果用户同意，就可以向他们发送通知
          const notifiy = new Notification(title, {
            body,
            icon,
          })
          if (callBack) {
            notifiy.onclick = function () {
              callBack()
              notifiy.close()
            }
          }
          resolve()
        } else {
          if (permission === 'denied') {
            console.log('Permission wasn\'t granted. Allow a retry.')
          } else if (permission === 'default') {
            console.log('The permission request was dismissed.')
          }
          reject()
        }
      })
    } else {
      reject()
    }
  })
}

function showToast(opt) {
  if (AppVisibility.appVisible) {
    Notify.create(opt)
  } else {
    tryNotify({ title: opt.message, ...opt })
  }
}

function getShowFn(opt, type = 'info') {
  if (typeof opt === 'string') {
    opt = { message: opt }
  }
  if (type === 'warning') {
    opt.icon = mdiAlertOutline
  }
  showToast({ ...opt, textColor: type || 'primary', type, color: 'white' })
}

function notifySuccess(opt) {
  getShowFn(opt, 'positive')
}

function notifyInfo(opt) {
  getShowFn(opt, 'info')
}

function notifyWarning(opt) {
  getShowFn(opt, 'warning')
}

function notifyError(opt) {
  getShowFn(opt, 'negative')
}

function doDownload(urlOrBlob, fileName) {
  let url = urlOrBlob
  if (typeof urlOrBlob !== 'string') {
    if (window.navigator.msSaveOrOpenBlob) {
      return window.navigator.msSaveOrOpenBlob(urlOrBlob, fileName)
    }
    url = URL.createObjectURL(urlOrBlob)
  }
  const alink = document.createElement('a')
  alink.download = fileName
  alink.href = url
  alink.style.display = 'none'
  document.body.appendChild(alink)
  alink.click()
  document.body.removeChild(alink)
  URL.revokeObjectURL(url)
}

function copy(txt) {
  copyToClipboard(txt)
    .then(() => {
      notifySuccess('已复制')
    })
    .catch(() => {
      notifyWarning('复制失败（该升级浏览器了！）')
    })
}

function toURLSearchParams(obj) {
  const urlPs = new URLSearchParams()
  for (const attr in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, attr) && typeof obj[attr] !== 'object') {
      urlPs.set(attr, obj[attr])
    }
  }
  return urlPs
}

function dataURLtoBlob(dataurl) {
  const arr = dataurl.split(',')
  const bstr = atob(arr[1], 'base64')
  let n = bstr.length
  const mime = arr[0].match(/:(.*?);/)[1]
  const u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new Blob([ u8arr ], { type: mime })
}

function fileToDataUrl(file) {
  return new Promise((resolve, reject) => {
    try {
      const reader = new FileReader()
      reader.onload = function (e) {
        resolve(e.target.result)
      }
      reader.readAsDataURL(file)
    } catch (e) {
      reject('请确保导入的是正确的图片文件！')
    }
  })
}

function timer(time = 1000) {
  return new Promise((resolve) => {
    setTimeout(resolve, time)
  })
}

export {
  defContentType,
  setUserInfo,
  getUserInfo,
  defShowLoading,
  defHideLoading,
  defFail,
  defError,
  showToast,
  notifySuccess,
  notifyInfo,
  notifyWarning,
  notifyError,
  defFailTip,
  defErrorTip,
  doDownload,
  copy,
  createMittApp,
  msgKey,

  handleError,

  toURLSearchParams,
  dataURLtoBlob,
  fileToDataUrl,
  timer,
}
